﻿/* **********************************************************************************
 *
 * Copyright (c) WickedFlame Projects. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Microsoft Reciprocal License
 * for WickedFlame. A copy of the license can be found in the License.html file
 * at the root of this distribution. 
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Microsoft Reciprocal License for WickedFlame.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;

namespace Gencode.Controls.CollapsibleControl
{
	
	public class CollapsibleControlCollection : IList, ICollection, IEnumerable
	{
        CollapsibleItem[] listItems;
		CollapsibleControl collapsibleControl;

        public CollapsibleControlCollection(CollapsibleControl collapsibleControl)
		{
            this.collapsibleControl = collapsibleControl;
		}

		private void AddEmptyNodeToList()
		{
			if (listItems == null)
				listItems = new CollapsibleItem[0];

			CollapsibleItem[] tmp = new CollapsibleItem[listItems.Length + 1];

			for (int i = 0; i < listItems.Length; i++)
				tmp[i] = listItems[i];
			
			listItems = tmp;
		}

		#region IList Members
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public virtual int Add(CollapsibleItem value)
		{
			if (value != null)
			{
                value.Width = collapsibleControl.Width;
                AddEmptyNodeToList();
                listItems[listItems.Length - 1] = value;

				if (collapsibleControl != null)
				{
                    collapsibleControl.Panel.SuspendLayout();

                    collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                    collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);
                    listItems[listItems.Length - 1].Header.ListHeaderStateChanged += new ListHeaderStateChangedEventHandler(collapsibleControl.ListHeaderStateChanged);

					collapsibleControl.Panel.Controls.Add(listItems[listItems.Length - 1].Header);
					collapsibleControl.Panel.Controls.Add(listItems[listItems.Length - 1]);

                    collapsibleControl.Panel_Resize(null, new EventArgs());

                    collapsibleControl.Panel.ResumeLayout(false);
                    collapsibleControl.Panel.PerformLayout();
				}
			}
			if (listItems == null)
				return 0;

			return listItems.Length;
		}

		public virtual int AddRange(CollapsibleItem[] range)
        {
            if (range != null && range.Length > 0)
            {
                collapsibleControl.Panel.SuspendLayout();
                for (int i = 0; i < range.Length; i++)
                {
                    if (range[i] != null)
                    {
                        AddEmptyNodeToList();
                        listItems[listItems.Length - 1] = range[i];

						if (collapsibleControl != null)
						{
                            collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                            collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);

							collapsibleControl.Panel.Controls.Add(listItems[listItems.Length - 1].Header);
							collapsibleControl.Panel.Controls.Add(listItems[listItems.Length - 1]);
						}
                    }
                }
                collapsibleControl.Panel.ResumeLayout(false);
                collapsibleControl.Panel.PerformLayout();
            }

            if (listItems == null)
                return 0;

            return listItems.Length;
        }

		public void Clear()
		{
            collapsibleControl.Panel.SuspendLayout();

            collapsibleControl.Panel.Controls.Clear();

            collapsibleControl.Panel.ResumeLayout(false);
            collapsibleControl.Panel.PerformLayout();

			listItems = new CollapsibleItem[0];
		}

		public virtual bool Contains(CollapsibleItem value)
		{
			bool containsNode = false;
			if (listItems != null && listItems.Length > 0)
			{
				for (int i = 0; i < listItems.Length; i++)
				{
                    if (listItems[i] == value)
						containsNode = true;
				}
			}
			return containsNode;
		}

		public virtual int IndexOf(CollapsibleItem value)
		{
			int index = -1;
			if (listItems != null && listItems.Length > 0)
			{
				for (int i = 0; i < listItems.Length; i++)
				{
                    if (listItems[i] == value)
						index = i;
				}
			}
			return index;
		}

		public virtual void Insert(int index, CollapsibleItem value)
		{
            if (value != null)
			{
				if (listItems == null)
					listItems = new CollapsibleItem[1];

				CollapsibleItem[] tmp = new CollapsibleItem[listItems.Length];

				int nIndex = 0;
				for (int i = 0; i < listItems.Length; i++)
				{
					if (index == i)
						tmp[i] = value;
					else
					{
						tmp[i] = listItems[nIndex];
						nIndex++;
					}
				}

				listItems = tmp;

                //remova all items from control
                //and readd all items
                collapsibleControl.Panel.SuspendLayout();
                foreach (Control cont in collapsibleControl.Panel.Controls)
                {
                    if (cont is CollapsibleItem || cont is CollapsibleItemHeader)
                    {
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);
                        collapsibleControl.Panel.Controls.Remove(cont);
                    }
                }

				foreach (CollapsibleItem item in listItems)
                {
                    collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                    collapsibleControl.ControlResize += new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);

					collapsibleControl.Panel.Controls.Add(item.Header);
                    collapsibleControl.Panel.Controls.Add(item);
                }
                collapsibleControl.Panel.ResumeLayout(false);
                collapsibleControl.Panel.PerformLayout();
			}
			else
				throw new Exception("Value type is not of type Control.");
		}

		public bool IsFixedSize
		{
			get { return false; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public virtual void Remove(CollapsibleItem value)
		{
			if (listItems != null && listItems.Length >= 1)
			{
				CollapsibleItem[] tmp = new CollapsibleItem[listItems.Length - 1];
				int tmpIndex = 0;

                collapsibleControl.Panel.SuspendLayout();
				for (int i = 0; i < listItems.Length; ++i)
				{
                    if (listItems[i] != value)
                    {
                        tmp[tmpIndex] = listItems[i];
                        tmpIndex++;
                    }
                    else
                    {
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);

                        collapsibleControl.Panel.Controls.Remove(listItems[i].Header);
                        collapsibleControl.Panel.Controls.Remove(listItems[i]);
                    }
				}
                collapsibleControl.Panel.ResumeLayout(false);
                collapsibleControl.Panel.PerformLayout();
			}
			else
				throw new Exception("List is empty.");
		}

		public void RemoveAt(int index)
		{
			if ((IsReadOnly) || (IsFixedSize))
			{
				throw new NotSupportedException("List " +
				  "is either read-only or a fixed size.");
			}

			if (listItems != null && listItems.Length >= 1)
			{
				if ((listItems.Length - 1) < index)
					throw new ArgumentOutOfRangeException("Index is out of range.");

				CollapsibleItem[] tmp = new CollapsibleItem[listItems.Length - 1];
				int tmpIndex = 0;

                collapsibleControl.Panel.SuspendLayout();
				for (int i = 0; i < listItems.Length; ++i)
				{
					if (i != index)
					{
                        tmp[tmpIndex] = listItems[i];
						tmpIndex++;
                    }
                    else
                    {
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].OnResize);
                        collapsibleControl.ControlResize -= new CollapsibelControlResizeEventHandler(listItems[listItems.Length - 1].Header.OnResize);

                        collapsibleControl.Panel.Controls.Remove(listItems[i].Header);
                        collapsibleControl.Panel.Controls.Remove(listItems[i]);
                    }
				}
                collapsibleControl.Panel.ResumeLayout(false);
                collapsibleControl.Panel.PerformLayout();
			}
			else
				throw new Exception("List is empty.");
		}

		public virtual CollapsibleItem this[int index]
		{
			get
			{
                return listItems[index];
			}
			set
			{
				listItems[index] = value;
			}
		}

		#endregion

		#region ICollection Members

		/// <summary>
		/// copys the list to array starting at index
		/// </summary>
		/// <param name="array"></param>
		/// <param name="index"></param>
		public void CopyTo(Array array, int index)
		{
			if (listItems != null)
			{
				if (index < 0 || index >= listItems.Length)
					throw new ArgumentOutOfRangeException("The index is out of range.");
				if (array.Length < (this.Count - index) + 1)
					throw new ArgumentException("Array cannot hold all values.");

				int i = 0;
				for (; index < listItems.Length; index++)
				{
					array.SetValue(listItems[index], i);
					i++;
				}
			}
			else
				throw new Exception("No nodes avaliabel.");
		}

		public int Count
		{
			get
			{
				if (listItems == null)
					return 0;
				return listItems.Length;
			}
		}

		public bool IsSynchronized
		{
			get { throw new NotImplementedException(); }
		}

		public Control SyncRoot
		{
			get { throw new NotImplementedException(); }
		}

		#endregion

		#region IEnumerable Members

		public IEnumerator GetEnumerator()
		{
            return new CollapsibleControlEnumerator(this);
		}

		#endregion

		#region IList Members

		int IList.Add(object value)
		{
			if (value != null && value is CollapsibleItem)
			{
				return Add((CollapsibleItem)value);
			}
			return 0;
		}

		bool IList.Contains(object value)
		{
			if (value != null && value is CollapsibleItem)
			{
				return Contains((CollapsibleItem)value);
			}
			return false;
		}

		int IList.IndexOf(object value)
		{
			if (value != null && value is CollapsibleItem)
			{
				return IndexOf((CollapsibleItem)value);
			}
			return -1;
		}

		void IList.Insert(int index, object value)
		{
			if (value != null && value is CollapsibleItem)
			{
				Insert(index, (CollapsibleItem)value);
			}
		}

		void IList.Remove(object value)
		{
			if (value != null && value is CollapsibleItem)
			{
				Remove((CollapsibleItem)value);
			}
		}

		object IList.this[int index]
		{
			get
			{
				return this[index];
			}
			set
			{
				if (value != null && value is CollapsibleItem)
				{
					this[index] = (CollapsibleItem)value;
				}
			}
		}

		#endregion

		#region ICollection Members

		object ICollection.SyncRoot
		{
			get
			{
				return SyncRoot;
			}
		}

		#endregion
	}
}
